require 'easy_form/i18n_cache'
module EasyForm
  module Inputs
    class Base
      # include 添加实例方法
      # extend  添加类方法
      include ERB::Util
      include ActionView::Helpers::TranslationHelper
      extend EasyForm::I18nCache

      include EasyForm::Helpers::Required
      include EasyForm::Helpers::Validators
      include EasyForm::Helpers::Readonly
      include EasyForm::Helpers::Disabled
      include EasyForm::Helpers::Autofocus

      include EasyForm::Components::LabelInput
      include EasyForm::Components::Errors
      include EasyForm::Components::Readonly
      include EasyForm::Components::Minlength
      include EasyForm::Components::Maxlength
      include EasyForm::Components::Pattern
      include EasyForm::Components::Placeholders
      include EasyForm::Components::MinMax

      attr_reader :attribute_name, :input_type, :column,
                  :options, :reflection, :input_html_classes,
                  :input_html_options, :html_classes
      delegate :template, :object, :object_name, :lookup_model_names, :lookup_action, to: :@builder
      class_attribute :default_options
      self.default_options = {}

      def self.enable(*keys)
        options = self.default_options.dup
        keys.each { |key| options.delete(key) }
        self.default_options = options
      end

      def self.disable(*keys)
        options = self.default_options.dup
        keys.each { |key| options[key] = false }
        self.default_options = options
      end

      disable :maxlength, :minlength, :placeholder, :pattern, :min_max
      def initialize(builder, attribute_name, column, input_type, options = {})
        @builder = builder
        @attribute_name = attribute_name
        @column = column
        @input_type = input_type
        @reflection = options.delete(:reflection)
        @options = options.reverse_merge!(self.class.default_options)
        @required = calculate_required
        @html_classes = EasyForm.additional_classes_for(:input) { additional_classes }
        @input_html_classes = @html_classes.dup

        if EasyForm.input_class && @input_html_classes.present?
          @input_html_classes << EasyForm.input_class
        end

        @input_html_options = html_options_for(:input, @input_html_classes).tap do |o|
          o[:readonly] = true if has_readonly?
          o[:disabled] = true if has_disabled?
          o[:autofocus] = true if has_autofocus?
        end
      end

      def additional_classes
        @additional_classes ||= [input_type, required_class, readonly_class, disabled_class].compact
      end

      def html_options_for(namespace, css_classes)
        html_options = options[:"#{namespace}_html"]
        html_options = html_options ? html_options.dup : {}
        css_classes << html_options[:class] if html_options.has_key?(:class)
        html_options[:class] = css_classes if !css_classes.empty?
        html_options
      end

      def input(wrapper_options = {})
        raise 'input方法必需实现！'
      end

      def input_class
        "#{lookup_model_names.join('_')}_#{reflection_or_attribute_name}"
      end

      def merge_wrapper_options(options, wrapper_options)
        return options unless wrapper_options
        wrapper_options = set_input_classes(wrapper_options)
        #合并参数
        wrapper_options.merge(options) do |key, oldval, newval|
          case key.to_s
          when 'class' #class属性是数组，合并时新旧值相加
            Array(oldval) + Array(newval)
          when 'data', 'aria' #data、aria属性是hash, 合并时以新值为主
            oldval.merge(newval)
          else
            newval
          end
        end
      end

      def set_input_classes(wrapper_options)
        wrapper_options = wrapper_options.dup
        error_class = wrapper_options.delete(:error_class)
        valid_class = wrapper_options.delete(:valid_class)

        if error_class.present? && has_errors?
          wrapper_options[:class] = "#{wrapper_options[:class]} #{error_class}"
        end
        if valid_class.present? && valid?
          wrapper_options[:class] = "#{wrapper_options[:class]} #{valid_class}"
        end
        wrapper_options
      end

      private
      def limit
        return unless column
        column.limit
      end

      def nested_boolean_style?
        options.fetch(:boolean_style, EasyForm.boolean_style) == :nested
      end

      def translate_from_namespace(namespace, default = '')
        model_names = lookup_model_names.dup
        lookups = []
        while model_names.present?
          name = model_names.join('.')
          model_names.shift
          lookups << :"#{name}.#{lookup_action}.#{reflection_or_attribute_name}"
          lookups << :"#{name}.#{reflection_or_attribute_name}"
        end
        lookups << :"defaults.#{lookup_action}.#{reflection_or_attribute_name}"
        lookups << :"defaults.#{reflection_or_attribute_name}"
        lookups << default

        I18n.t(lookups.shift, scope: :"#{i18n_scope}.#{namespace}", default: lookups).presence
      end

      def reflection_or_attribute_name
        @reflection_or_attribute_name ||= reflection ? reflection.name : attribute_name
      end

      def self.i18n_scope
        EasyForm.i18n_scope
      end
      def i18n_scope
        EasyForm.i18n_scope
      end
    end
  end
end